using System;
using System.IO;
using System.Linq;
using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEditorInternal;
using UnityEngine;
using LS.UnityExtensions.Editor;
using Type = System.Type;

namespace LS.Editor
{
    [CustomEditor(typeof(DataTableGeneratingCollection))]
    public class DataTableGeneratingCollectionInspector : InspectorBase
    {
        private static class Content
        {
            public static readonly string Title = "DataTableCollections (bool GenerateCodeFile, TextAsset GataTableFiles)";
            public static readonly string PropertyName = "m_DataTableNameCollections";

            public static readonly string FileInfo_Guid = "m_GUID";
            public static readonly string FileInfo_Name = "m_Name";
            public static readonly string FileInfo_Extension = "m_Extension";
            public static readonly string FileInfo_FilePath = "m_FilePath";

            public static readonly string GenerateToggleTip = "OnGenerate";
        }

        private static class Style
        {
            public static readonly float GenerateToggleWidth = 20;
        }

        private List<DataTableAssetHolder> m_DataTableFileCollection;
        private ReorderableList m_FilesList;

        private SerializedProperty m_NameListProperty;
        private Type m_TextAssetType = typeof(TextAsset);

        protected override void OnEnable()
        {
            base.OnEnable();
            m_NameListProperty = serializedObject.FindProperty(Content.PropertyName);
            m_DataTableFileCollection = new List<DataTableAssetHolder>(m_NameListProperty.arraySize);

            for (int i = 0; i < m_NameListProperty.arraySize; i++)
            {
                var element = m_NameListProperty.GetArrayElementAtIndex(i);
                DataTableFileInfo value = (DataTableFileInfo)element.boxedValue;
                var guid = new GUID(value.AssetGuid);
                var holder = new DataTableAssetHolder(guid);
                holder.EnableGenerate = value.EnableGenerate;
                m_DataTableFileCollection.Add(holder);
            }

            m_FilesList = new ReorderableList(m_DataTableFileCollection, typeof(DataTableAssetHolder));

            m_FilesList.elementHeightCallback = index =>
            {
                var content = EditorGUIUtility.ObjectContent(m_DataTableFileCollection[index].Asset, m_TextAssetType);
                return EditorGUI.GetPropertyHeight(SerializedPropertyType.ObjectReference, content) + EditorGUIUtility.standardVerticalSpacing;
            };
            m_FilesList.drawHeaderCallback = rect => EditorGUI.LabelField(rect, Content.Title);

            m_FilesList.drawElementCallback = (rect, index, active, focused) =>
            {
                Rect ofRect = new Rect(rect.x + Style.GenerateToggleWidth, rect.y, rect.width - Style.GenerateToggleWidth, rect.height);
                Rect toggleRect = new Rect(rect.x, rect.y, Style.GenerateToggleWidth, rect.height);
                var holder = m_DataTableFileCollection[index];
                bool enableGenerate = EditorGUI.Toggle(toggleRect, holder.EnableGenerate);
                var newAsset = EditorGUI.ObjectField(ofRect, holder.Asset, m_TextAssetType, false);

                if (enableGenerate != holder.EnableGenerate)
                {
                    holder.EnableGenerate = enableGenerate;
                }

                if (newAsset != holder.Asset)
                {
                    holder.Update((TextAsset)newAsset);
                }
            };
        }

        public override void DrawInspectorItems()
        {
            this.serializedObject.UpdateIfRequiredOrScript();
            m_FilesList.DoLayoutList();
        }

        public override void OnPropertyValueChanged()
        {
            base.OnPropertyValueChanged();
            var collection = (this.target as DataTableGeneratingCollection).Collection;

            while (collection.Count > m_DataTableFileCollection.Count)
            {
                collection.RemoveAt(collection.Count - 1);
            }

            while (collection.Count < m_DataTableFileCollection.Count)
            {
                collection.Add(new DataTableFileInfo());
            }

            for (int i = 0; i < m_DataTableFileCollection.Count; i++)
            {
                var holder = m_DataTableFileCollection[i];
                var item = collection[i];
                ApplayFileInfo(item, holder);
            }

            EditorUtility.SetDirty(this.target);
        }

        public override void DrawInspectorFinish()
        {
            base.DrawInspectorFinish();
            AssetDatabase.SaveAssetIfDirty(this.target);
        }

        private void ApplayFileInfo(DataTableFileInfo content, DataTableAssetHolder reference)
        {
            string path = reference.Path;
            string name = Path.GetFileNameWithoutExtension(path);
            string extension = Path.GetExtension(path);

            content.Name = name;
            content.EnableGenerate = reference.EnableGenerate;
            content.Extension = extension;
            content.FilePath = path;
            content.AssetGuid = reference.GUID.ToString();

        }

        [Serializable]
        public class DataTableAssetHolder : IDisposable
        {
            private TextAsset m_Asset;
            private GUID m_Guid;

            private bool m_EnableGenerate = false;

            private bool m_Available;

            public bool IsMissing
            {
                get
                {
                    return m_Available && m_Asset == null && m_Guid.Empty() == false;
                }
            }

            public bool IsEmpty
            {
                get
                {
                    return m_Asset == null;
                }
            }

            public bool Available
            {
                get
                {
                    return m_Available;
                }
            }

            public bool EnableGenerate
            {
                get
                {
                    return m_EnableGenerate;
                }
                set
                {
                    m_EnableGenerate = value;
                }
            }

            public GUID GUID => m_Guid;
            public TextAsset Asset => m_Asset;
            public string Path => AssetDatabase.GUIDToAssetPath(m_Guid);

            public DataTableAssetHolder(GUID guid)
            {
                m_Guid = guid;
                m_Available = true;
                m_Asset = null;
                if (!guid.Empty())
                {
                    string path = AssetDatabase.GUIDToAssetPath(guid);
                    m_Asset = AssetDatabase.LoadAssetAtPath<TextAsset>(path);
                }
            }

            public DataTableAssetHolder(TextAsset asset)
            {
                m_Guid = default;
                m_Asset = null;
                m_Available = true;
                if (asset != null)
                {
                    string path = AssetDatabase.GetAssetPath(asset);
                    m_Guid = AssetDatabase.GUIDFromAssetPath(path);
                }
            }

            public DataTableAssetHolder(string assetPath)
            {
                m_Guid = default;
                m_Asset = null;
                m_Available = true;
                if (!string.IsNullOrEmpty(assetPath))
                {
                    m_Guid = AssetDatabase.GUIDFromAssetPath(assetPath);
                    m_Asset = AssetDatabase.LoadAssetAtPath<TextAsset>(assetPath);
                }
            }

            public DataTableAssetHolder()
            {
                m_Guid = default;
                m_Asset = null;
                m_Available = false;
            }

            public void Update(GUID guid)
            {
                m_Guid = guid;
                string path = AssetDatabase.GUIDToAssetPath(guid);
                m_Asset = AssetDatabase.LoadAssetAtPath<TextAsset>(path);
                m_Available = true;
            }

            public void Update(TextAsset asset)
            {
                m_Asset = asset;
                string path = AssetDatabase.GetAssetPath(asset);
                m_Guid = AssetDatabase.GUIDFromAssetPath(path);
                m_Available = true;
            }

            public void Update(string path)
            {
                m_Guid = AssetDatabase.GUIDFromAssetPath(path);
                m_Asset = AssetDatabase.LoadAssetAtPath<TextAsset>(path);
                m_Available = true;
            }

            public void Dispose()
            {
                m_Available = false;
                m_Guid = default;
                m_Asset = null;
                m_EnableGenerate = false;
            }
        }
    }
}
